package com.fit.spring.boot.properties.autoscan.autoconfigure;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.fit.spring.boot.properties.autoscan.utils.IOUtil;


/**
 * 扫描properties配置文件,将配置项加入到Environment中
 * PS:
 * 	如果properties的classpath名称('class path resource ["classpath"]')相同时, 覆盖操作。
 *  覆盖操作时,外部项目中的文件优先级高于jar包中classpath相同的文件。
 * @author hcl
 *
 */
public class AutoScanLoadSourceConfiguration implements EnvironmentPostProcessor{

	private static Logger log = LoggerFactory.getLogger(AutoScanLoadSourceConfiguration.class);
	
	/**
	 * 初始化Environment
	 */
	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		String classPath = "";
		try {
			classPath = new ClassPathResource(classPath).getFile().toURI().toString();
		} catch (IOException e) {
			log.error("读取classpath路径异常！",e);
		}
		MutablePropertySources mutablePropertySources = environment.getPropertySources();
		
		List<AutoScanPropertiesProperties> propertiesAll = new ArrayList<AutoScanPropertiesProperties>();
		
		//获取系统配置
		AutoScanPropertiesProperties sysProperties = AutoScanPropertiesProperties.getMainSysProperties(environment);
		propertiesAll.add(sysProperties);
		
		//获取扩展配置
		List<AutoScanPropertiesProperties> extensionProperties = AutoScanPropertiesProperties.getAutoScanPropertiesProperties();
		propertiesAll.addAll(extensionProperties);
		
		for(AutoScanPropertiesProperties properties : propertiesAll){
			if(properties.getEnabled()){
				List<String> locations = new ArrayList<String>();
				locations.add(properties.getLocations());
				String[] activeProfiles = environment.getActiveProfiles();
				if(activeProfiles != null){
					for(String activeProfile : activeProfiles){
						if(AutoScanPropertiesProperties.SpringProfilesActiveType.DEV.getName().equals(activeProfile.toLowerCase())){
							locations.add(properties.getDevLocations());
						}else if(AutoScanPropertiesProperties.SpringProfilesActiveType.TEST.getName().equals(activeProfile.toLowerCase())){
							locations.add(properties.getTestLocations());
						}else if(AutoScanPropertiesProperties.SpringProfilesActiveType.PROD.getName().equals(activeProfile.toLowerCase())){
							locations.add(properties.getProLocations());
						}
					}
				}
				for(String location : locations){
					this.addPropertySource(location, classPath, mutablePropertySources);
				}
			}
		}
	}
	
	
	/**
	 * 根据路径添加配置文件
	 * @param location
	 * @param classPath
	 * @param mutablePropertySources
	 */
	private void addPropertySource(String location, String classPath, MutablePropertySources mutablePropertySources){
		if(location == null || location.trim().equals("")){
			return ;
		}
		String[] locationsArr = location.split(",");
		for(String locationsPath : locationsArr){
			PathMatchingResourcePatternResolver configProperties = new PathMatchingResourcePatternResolver();
			Resource[] configSources;
			try {
				configSources = configProperties.getResources(locationsPath.trim());
				for(Resource resource : configSources){
					String uri = resource.getURI().toString();
					if(log.isDebugEnabled()){
						log.debug("加载配置文件：'{}'" , uri);
					}
					//同名情况下是否优先
					boolean priority = false;
					int classPathIndex = uri.lastIndexOf(classPath);
					if(classPathIndex >= 0){
						//此处不是jar包中配置,优先级比jar包中配置高,所以此处为true
						priority = true;
						uri = uri.substring(classPathIndex + classPath.length());
					}
					uri = uri.substring(uri.lastIndexOf("!")+1);
					if(uri.startsWith("/")){
						uri = uri.substring(1);
					}
					String name = "class path"+( priority ? "" : "*" )+" resource [" + uri +"]";
					
					if(priority || mutablePropertySources.get(name) == null){
						InputStream in = null;
						try{
							if(uri.endsWith(".yml") || uri.endsWith(".yaml")){
								YamlPropertySourceLoader yamlSource = new YamlPropertySourceLoader();
								mutablePropertySources.addLast(yamlSource.load(name, resource, null));
							}else if(uri.endsWith(".properties")){
								in = resource.getInputStream();
								Properties pro = new Properties();
								pro.load(in);
								PropertiesPropertySource propertySource = new PropertiesPropertySource(name, pro);
								mutablePropertySources.addLast(propertySource);
							}else{
								throw new RuntimeException("此文件'"+uri+"'后缀不支持加载!");
							}
							log.debug("加载 '{}' 配置文件成功!" , name);
						}catch (Exception e) {
							log.error("加载 '{}' 配置文件异常!",name, e);
						}finally{
							IOUtil.close(in);
						}
					}
				}
			} catch (IOException e) {
				log.error("资源 '{}' 扫描异常！",locationsPath, e);
			}
		}
	}
	

}
